package cn.jbolt.core.util;

import cn.hutool.core.util.StrUtil;
import cn.jbolt.core.bean.IpRegion;
import cn.jbolt.core.map.BaiduMapApi;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.lang.reflect.Method;
import java.net.*;
import java.util.Enumeration;
import java.util.List;

/**
 * IP工具类
 */
public class JBoltIpUtil {

	/**
	 * 获取登录用户的IP地址
	 *
	 * @param request
	 * @return
	 */
	public static String getIp(HttpServletRequest request) {
		if (request == null) {
			return "unknown";
		}
		String ip = request.getHeader("x-forwarded-for");
		if (!isValidAddress(ip)) {
			ip = null;
		}

		if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
			if (!isValidAddress(ip)) {
				ip = null;
			}
		}

		if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
			if (!isValidAddress(ip)) {
				ip = null;
			}
		}

		if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTPCLIENTIP");
			if (!isValidAddress(ip)) {
				ip = null;
			}
		}
		if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Real-IP");
			if (!isValidAddress(ip)) {
				ip = null;
			}
		}

		if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
			if (!isValidAddress(ip)) {
				ip = null;
			}
		}

		if (ip == null) {
			return "unknown";
		}

		if ("0:0:0:0:0:0:0:1".equals(ip)) {
			return "127.0.0.1";
		}

		if (ip.indexOf(",") != -1) {
			String[] ipArr = ip.split(",");
			if (ipArr != null && ipArr.length > 0) {
				ip = ipArr[0];
				if (!isValidAddress(ip)) {
					ip = null;
				}
			}
		}
		if (StrKit.isBlank(ip)) {
			return "unknown";
		}
		if (!isValidAddress(ip)) {
			ip = "unknown";
		}
		return ip;
	}

	/**
	 * 是否符合ip格式
	 *
	 * @param ip
	 * @return
	 */
	public static boolean isValidAddress(String ip) {
		if (StrKit.isBlank(ip)) {
			return false;
		}

		for (int i = 0; i < ip.length(); ++i) {
			char ch = ip.charAt(i);
			if (ch >= '0' && ch <= '9') {
			} else if (ch >= 'A' && ch <= 'F') {
			} else if (ch >= 'a' && ch <= 'f') {
			} else if (ch == '.' || ch == ':') {
				//
			} else {
				return false;
			}
		}

		return true;
	}

	/**
	 * 使用Ip2Region
	 *
	 * @param ip
	 * @return
	 */
	public static IpRegion toAddressByIp2Region(String ip) {
		// db
		String dbPath = JBoltIpUtil.class.getResource("/ip2region/ip2region.db").getPath();
		File file = new File(dbPath);
		if (file.exists() == false) {
			LogKit.error("Invalid ip2region.db file {}", dbPath);
			return null;
		}

		// 查询算法
		int algorithm = DbSearcher.BTREE_ALGORITHM; // B-tree
		// DbSearcher.BINARY_ALGORITHM //Binary
		// DbSearcher.MEMORY_ALGORITYM //Memory
		try {
			DbConfig config = new DbConfig();
			DbSearcher searcher = new DbSearcher(config, dbPath);

			// define the method
			Method method = null;
			switch (algorithm) {
			case DbSearcher.BTREE_ALGORITHM:
				method = searcher.getClass().getMethod("btreeSearch", String.class);
				break;
			case DbSearcher.BINARY_ALGORITHM:
				method = searcher.getClass().getMethod("binarySearch", String.class);
				break;
			case DbSearcher.MEMORY_ALGORITYM:
				method = searcher.getClass().getMethod("memorySearch", String.class);
				break;
			}

			DataBlock dataBlock = null;
			if (Util.isIpAddress(ip) == false) {
				LogKit.error("Invalid ip address,IP={}", ip);
			}

			dataBlock = (DataBlock) method.invoke(searcher, ip);
			String region = dataBlock.getRegion();
			IpRegion ipRegion = new IpRegion();
			List<String> regions = StrUtil.split(region, '|');
			ipRegion.setIp(ip);
			ipRegion.setCountry(regions.get(0));
			ipRegion.setProvince(regions.get(2));
			ipRegion.setCity(regions.get(3));
			ipRegion.setIsp(regions.get(4));
			searcher.close();
			return ipRegion;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * 通过IP获取位置
	 *
	 * @param ip
	 * @return
	 */
	public static JSONObject toAddressByBaiduMapApi(String ip) {
		return BaiduMapApi.ipToAddress(ip);
	}

	/**
	 * 获取服务器主机外网IP
	 *
	 * @return
	 */
	public static String getServerIp() {
		try {
			Enumeration<NetworkInterface> networks = NetworkInterface.getNetworkInterfaces();
			Enumeration<InetAddress> addrs;
			InetAddress ip;
			while (networks.hasMoreElements()) {
				addrs = networks.nextElement().getInetAddresses();
				while (addrs.hasMoreElements()) {
					ip = addrs.nextElement();
					if (ip instanceof Inet4Address && !ip.isSiteLocalAddress() && !ip.isLoopbackAddress()) {
						// 从网卡获取外网IP
						return ip.getHostAddress();
					}
				}
			}
		} catch (SocketException e) {
			e.printStackTrace();
			return "127.0.0.1";
		}

		try {
			// 外网IP不存在，那么获取内网IP
			return InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
			return "127.0.0.1";
		}
	}

	public static void main(String[] args) {
		System.out.println(JsonKit.toJson(toAddressByBaiduMapApi("172.104.125.185")));
	}

}
